classdef JsonObject< handle & matlab.mixin.Copyable
    
    properties
        json_data;
        dirpath;
        pureName;
        lowQuality = 35;
        highQuality = 95;
    end
    methods
        function obj = JsonObject(fileName, reOrder, reChangCellToStruct) %返回值必须是一个obj
            obj.json_data = jsondecode(fileread(fileName));
            [dirpath, Name, ~] = fileparts(fileName);
            
            obj.dirpath = dirpath;
            obj.pureName = Name;
            
            if nargin >1%%重整每个box的坐标，使得左上角最小
                if reOrder == true
                    obj.reOrderPoints();
                end
            end
            if nargin >2%%重整数组，发现93w.json是cell数组，要转换为struct数组
                if reChangCellToStruct == true
                    shapes = obj.json_data.shapes;
                    if isempty(shapes)
                        return;
                    end
                    if iscell(shapes) == false
                        return;
                    end
                    data = {};
                    for i = 1 : length(shapes)                             
                        shape = shapes{i};
                        
                        if isempty(data)
                            data = struct(shape);
                        else
                            data(end+1, 1) = shape;
                        end
                    end
                    obj.json_data.shapes = data;
                end
            end
            
        end
        %% 调整shapes中的points的坐标大小（因为labelme并不是最小的放左上角，可能再右下角）
        function reOrderPoints(obj)
            shapes = obj.json_data.shapes;
            
            for i = 1 : size(shapes, 1)
                shape = shapes(i);
                pts = shape.points;
                label = shape.label;
                if strcmp(label, 'circle') == true
                    continue;
                end
                
                pts(1, :) = min(shape.points);
                pts(2, :) = max(shape.points);
                
                obj.json_data.shapes(i).points = pts;
                obj.json_data.shapes(i).group_id = nan;
            end
        end
        
        %% 获取形状
        function shapes = get_shapes(obj)
            shapes = obj.jso_data.shapes;
        end
        
        %% 是否有种子
        function bRet = hasShapes(obj)
            shapes = obj.json_data.shapes;
            bRet = ~isempty(shapes);
        end
        %% 是否都是partial
        function bRet = hasAllPartials(obj)
            bRet = false;
            
            shapes = obj.json_data.shapes;
            
            for i = 1 : size(shapes, 1)
                shape = shapes(i);
                
                label = shape.label;
                if strcmp(label, 'partial') == false
                    return;
                end
            end
            bRet = true;
        end
        
        %% 是否有单叶
        function bRet = hasSingleLeaf(obj)
            bRet = false;
            
            shapes = obj.json_data.shapes;
            
            for i = 1 : size(shapes, 1)
                shape = shapes(i);
                
                label = shape.label;
                if strcmp(label, 'seed_1') == true
                    bRet = true;
                    return;
                end
            end
        end
        
        function nRet = numOfSingleLeaf(obj)
            nRet = 0;
            
            shapes = obj.json_data.shapes;
            for i = 1 : size(shapes, 1)
                shape = shapes(i);
                label = shape.label;
                if strcmp(label, 'seed_1') == true
                    nRet = nRet + 1;
                end
            end
        end
        
        %%左右翻转
        function img = fliplrImage(obj, img)
            if nargin >1
                img = fliplr(img);
            end
            
            shapes = obj.json_data.shapes;
            
            imageWidth = obj.json_data.imageWidth;
            imageHeight = obj.json_data.imageHeight;
            
            for i = 1 : size(shapes, 1)
                shape = shapes(i);
                box = shape.points;
                label = shape.label;
                if strcmp(label, 'circle') == true
                    continue;
                end
                
                points = JsonObject.FliplrImage(box, imageWidth);
                
                obj.json_data.shapes(i).points = points;
                obj.json_data.shapes(i).group_id = nan;
            end
            
        end
        
        %%逆时针旋转
        function img = rotateImage90(obj, img)
            if nargin >1
                img = rot90(img);
            end
            shapes = obj.json_data.shapes;
            
            imageWidth = obj.json_data.imageWidth;
            imageHeight = obj.json_data.imageHeight;
            
            for i = 1 : size(shapes, 1)
                shape = shapes(i);
                box = shape.points;
                label = shape.label;
                if strcmp(label, 'circle') == true
                    continue;
                end
                
                points = JsonObject.RotateImage90(box, imageWidth);
                
                obj.json_data.shapes(i).points = points;
                obj.json_data.shapes(i).group_id = nan;
            end
            
            
            obj.json_data.imageWidth = imageHeight;
            obj.json_data.imageHeight = imageWidth;
        end
        
        function imagePath = get_imagePath(obj)
            imagePath = obj.json_data.imagePath;
        end
        
        function img = getImage(obj)
            imgFile = fullfile(obj.dirpath, obj.json_data.imagePath);
            img = imread(imgFile);
        end
        
        %%增加附加数据
        function setAttachedData(obj, box, overlap)
            obj.json_data.mybox = box;
            obj.json_data.myoverlap = overlap;
        end
        %%图片数据 base64编码
        %% fileName 保存路径全路径
        function encodeImageData(obj, img, fileName, isLowHigh)
            [~,name,ext] = fileparts(fileName);
            
            obj.json_data.imagePath = [name, ext];
            
            if isLowHigh == true %%低质量编码减少文件大小，
                imwrite(img, fileName, 'Quality', obj.lowQuality);
            else%%用默认压缩 75
                imwrite(img, fileName);
            end
            fid = fopen(fileName, 'r');
            A = fread(fid);
            res = matlab.net.base64encode(A);
            obj.json_data.imageData = res;
            fclose(fid);
            
            if isLowHigh == true %%用默认压缩 95保存图片
                imwrite(img, fileName, 'Quality', obj.highQuality);
            end
        end
        %%Json文件保存
        function saveJsonFile(obj, fileName)
            shapes = obj.json_data.shapes;
            
            flag = false;
            if isstruct(shapes) && length(shapes) == 1%%对单个元素增加一层数组
                tmpppp = shapes;
                obj.json_data.shapes = {shapes};
                flag = true;
            end
            
            txt = jsonencode(obj.json_data);
            fid = fopen(fileName, 'wt');
            fprintf(fid, '%s', txt);
            fclose(fid);
            
            if flag == true
                obj.json_data.shapes = tmpppp;
            end
        end
        
        % % % % % % % % % % % % % % % % %
        % % % % 截取 单叶图片
        function imgs = cutSingleLeaf(obj, img)
            shapes = obj.json_data.shapes;
            
            imgs = {};
            kk = 1;
            for i = 1 : size(shapes,1)
                shape = shapes(i);
                label = shape.label;
                
                if strcmp(label, 'seed_1') == false
                    continue;
                end
                
                pts = shape.points;
                rect = JsonObject.CalcRectInImage(pts);
                imgs{kk} = imcrop(img, rect);
                kk = kk + 1;
            end
        end
        % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % %
        %% 统计种子数量
        function stat = statSeeds(obj)
            shapes = obj.json_data.shapes;
            
            stat.seed = 0;
            stat.seed_1 = 0;
            stat.partial = 0;
            stat.circle = 0;
            
            
            stat.sideMax = 0;
            stat.sideMin = obj.json_data.imageHeight;
            stat.areaMax = 0;
            stat.areaMin = obj.json_data.imageHeight * obj.json_data.imageWidth;
            
            areas = [];
            saveWH = [];
            saveLeaf1 = [];
            for i = 1 : size(shapes,1)
                shape = shapes(i);
                label = shape.label;
                
                if strcmp(label, 'circle') == true
                    stat.circle = stat.circle  + 1;
                    continue;
                end
                if strcmp(label, 'seed') == true
                    stat.seed = stat.seed + 1;
                elseif strcmp(label, 'seed_1') == true
                    stat.seed_1 = stat.seed_1 + 1;
                elseif strcmp(label, 'partial') == true
                    stat.partial = stat.partial + 1;
                end
                pts = shape.points;
                wwhh = pts(2, :) - pts(1, :);
                wwhh = abs(wwhh);
                ww = max(wwhh);
                hh = min(wwhh);
                area = ww*hh;
                
                if ww > stat.sideMax
                    stat.sideMax = ww;
                end
                if hh < stat.sideMin
                    stat.sideMin = hh;
                end
                if area > stat.areaMax
                    stat.areaMax = area;
                end
                if area < stat.areaMin
                    stat.areaMin = area;
                end
                
                areas(end+1) = area;
                saveWH(end+1, :) = wwhh; %%[ww, hh];
                
                if strcmp(label, 'seed_1') == true
                    saveLeaf1(end+1, :) = wwhh;
                end
            end
            stat.areas = areas';
            stat.wwhh = saveWH;
            stat.whOne = saveLeaf1;
            
            %              stat(4:7) = [sideMax, sideMin, areaMax, areaMin];
        end
        
        %% 图片显示
        function showImage(obj, bShowRect)
            imgPath = [obj.dirpath, '\', obj.json_data.imagePath];
            img = imread(imgPath);
            image(img)
            axis equal
            
            if bShowRect == true
                obj.drawBoxes();
            end
        end
        %%画出矩形框
        function drawBoxes(obj)
            hold on
            shapes = obj.json_data.shapes;
            for i = 1 : size(shapes,1)
                shape = shapes(i);
                points = shape.points;
                label = shape.label;
                
                box = [points(1, 1)+1, points(1, 2)+1, ...
                    points(2,1) - points(1,1), points(2,2) - points(1,2)];
                if strcmp(label, 'seed') == true
                    rectangle('Position', box, 'EdgeColor','b')
                elseif strcmp(label, 'seed_1') == true
                    rectangle('Position', box, 'EdgeColor','r')
                elseif strcmp(label, 'partial') == true
                    rectangle('Position', box, 'EdgeColor','k')
                end
            end
            hold off
        end
        
        %%找出在指定矩形框中的 shape
        function retShapes = getShapesInRect(obj, rect, overlap)
            rect = rect';
            
            retShapes = {};
            % % %              ret = struct('label',{},'points',{},'group_id',{}, 'shape_type', {}, 'flags', {});
            shapes = obj.json_data.shapes;
            
            for i = 1 : size(shapes,1)
                shape = shapes(i);
                points = shape.points;
                label = shape.label;
                if strcmp(label, 'circle') == true
                    continue;
                end
                
                pp = points(:);
                if Helper.IsInRect(pp, rect)
                    shape.points(:, 1) = shape.points(:, 1) - rect(1);
                    shape.points(:, 2) = shape.points(:, 2) - rect(2);
                    retShapes{end+1, 1} = shape;
                    continue;
                end
                
                [bIn, inBox, ratio] = Helper.IsBoxMostInRect(pp, rect);
                if bIn == true
                    shape.points(:, 1) = inBox(1:2)' - rect(1);
                    shape.points(:, 2) = inBox(3:4)' - rect(2);
                    
                    if ratio<0.75
                        shape.label = 'partial';
                    end
                    retShapes{end+1, 1} = shape;
                end
                
            end
        end
        
        %%2022-12-12 转换成640；
        function img = convertTo640(self, dstWidth, dstHeight)
            
            srcHeight = self.json_data.imageHeight;
            srcWidth = self.json_data.imageWidth;
            
            ratioW = dstWidth/srcWidth;
            ratioH = dstHeight/srcHeight;
  
            shapes = self.json_data.shapes;
            for i = 1 : size(shapes, 1)
                shape = shapes(i);
                points = shape.points;
                points(:, 1) = points(:, 1) * ratioW;
                points(:, 2) = points(:, 2) * ratioH;                
                                
                self.json_data.shapes(i).points = points;
            end
            
            self.json_data.imageHeight = dstHeight;
            self.json_data.imageWidth = dstWidth;
           
            img = self.getImage();
            img = imresize(img, [dstHeight, dstWidth]);
            %%self.encodeImageData(img, self.json_data.imagePath, true);
        end
    end
    
    
    methods(Static = true)
        function rect = CalcRectInImage(box)
            rect = zeros(4, 1);
            rect(1) = box(1, 1) + 1;
            rect(2) = box(1, 2) + 1;
            rect(3) = box(2, 1) - box(1, 1) - 1;
            rect(4) = box(2, 2) - box(1, 2) - 1;
        end
        
        %% 翻转图片
        function box = FliplrImage(box, imageWidth)
            xa = box(1, 1);
            ya = box(1, 2);
            xc = box(2, 1);
            yc = box(2, 2);
            
            xd = xc;
            yd = ya;
            xb = xa;
            yb = yc;
            box = [[imageWidth-1 - xd, yd]; [imageWidth-1 - xb, yb]];
        end
        %%逆时针旋转图片
        function box = RotateImage90(box, imageWidth)
            xa = box(1, 1);
            ya = box(1, 2);
            xc = box(2, 1);
            yc = box(2, 2);
            
            xd = xc;
            yd = ya;
            xb = xa;
            yb = yc;
            
            box = [[yd, imageWidth- 1 - xd]; [yb, imageWidth- 1 - xb]];
        end
        
        
        
    end
end